Migo商城2.0 新增商品添加规格参数的实现 十二

Migo商城2.0 新增商品添加规格参数的实现 十二

页面展示规格参数模板

在商品添加或者商品修改时,根据商品的分类id查询此商品分类对应的规格参数模板。根据规格参数模板,生成一个表单供用户使用

迭代相应js代码

为实现restful风格 修改为ajax格式的,同时和其他功能公用同一个方法,改造访问URL url: "/rest/item/param/" + node.id

和上面对比应该发现,restful风格代码更加直观,逻辑处理更加清晰可见!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
changeItemParam : function(node,formId){
$.ajax({
type: "GET",
url: "/rest/item/param/" + node.id,
statusCode : {
200 : function(data){
$("#"+formId+" .params").show();
var paramData = JSON.parse(data.paramData);
var html = "<ul>";
for(var i in paramData){
var pd = paramData[i];
html+="<li><table>";
html+="<tr><td colspan=\"2\" class=\"group\">"+pd.group+"</td></tr>";

for(var j in pd.params){
var ps = pd.params[j];
html+="<tr><td class=\"param\"><span>"+ps+"</span>: </td><td><input autocomplete=\"off\" type=\"text\"/></td></tr>";
}

html+="</li></table>";
}
html+= "</ul>";
$("#"+formId+" .params td").eq(1).html(html);
},
404 : function(){
$("#"+formId+" .params").hide();
$("#"+formId+" .params td").eq(1).empty();
},
500 : function(){
alert("error");
}
}
});
},

展示效果

通过js代码把用户提交的数据生成json数据格式

上章有讲,可以对比下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//输入的规格参数数据保存为json
var paramJson = [];
$("#itemAddForm .params li").each(function(i,e){
var trs = $(e).find("tr");
var group = trs.eq(0).text();
var ps = [];
for(var i = 1;i<trs.length;i++){
var tr = trs.eq(i);
ps.push({
"k" : $.trim(tr.find("td").eq(0).find("span").text()),
"v" : $.trim(tr.find("input").val())
});
}
paramJson.push({
"group" : group,
"params": ps
});
});
paramJson = JSON.stringify(paramJson);

$("#itemAddForm [name=itemParams]").val(paramJson);

后台实现

只需要在Controller中添加一个参数,接收商品的规格参数即可。

Service中也需要添加一个参数,增加插入规格参数表的处理。

改造ItemService saveItem中 方法 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//desc参考前端页面传过来的数据是序列化成字符串的
public Boolean saveItem(Item item,String desc,String itemParams){
// 1、生成商品id
long itemId = IDUtils.genItemId();
// 2、对TbItem对象补全属性。
item.setId(itemId);

//'商品状态,1-正常,2-下架,3-删除'
item.setStatus(1);


//保存商品数据
Integer save = super.save(item);

ItemDesc itemDesc=new ItemDesc();
itemDesc.setItemDesc(desc);
itemDesc.setItemId(item.getId());

//保存商品描述数据
Integer save1 = this.itemDescService.save(itemDesc);

//保存商品规格参数数据
ItemParamItem itemParamItem=new ItemParamItem();
itemParamItem.setItemId(item.getId());
itemParamItem.setParamData(itemParams);
Integer save2 = this.itemParamItemService.save(itemParamItem);
return save.intValue()==1&&save1.intValue()==1&&save2==1;

}
改造controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 新增商品
*/
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<Void> addItem(Item item, @RequestParam("desc") String desc,
@RequestParam("itemParams") String itemParams) {

if (LOGGER.isInfoEnabled()) {
LOGGER.info("新增商品,item = {}, desc = {}", item, desc);
}
/**
* TODO 校验以后完善
*/
if (item.getPrice() == null || item.getPrice().intValue() == 0) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("新增商品时用户输入的参数不合法,item = {}, desc = {},itemParams", item, desc);
}
// 参数有误,返回400
//ResponseEntity<Void> build();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}

try {
Boolean saveItem = this.itemService.saveItem(item, desc,itemParams);
if (saveItem) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("新增商品成功! id = {}", item.getId());
}
//CREATED(201, "Created"),
return ResponseEntity.status(HttpStatus.CREATED).build();
}
} catch (Exception e) {
LOGGER.error("新增商品失败! item = " + item + ", desc = " + desc, e);
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}

运行项目,添加商品

数据库存储数据格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
[
{
"group": "主体",
"params": [
{
"k": "品牌",
"v": "OPPO"
},
{
"k": "型号",
"v": "R9s"
},
{
"k": "颜色",
"v": "黑色"
},
{
"k": "上市年份",
"v": "2016年"
}
]
},
{
"group": "网络",
"params": [
{
"k": "4G网络制式",
"v": "4G:移动(TD-LTE);4G:联通(FDD-LTE);4G:电信(FDD-LTE)"
},
{
"k": "3G网络制式",
"v": "3G:移动(TD-SCDMA);3G:联通(WCDMA);3G:电信(CDMA2000);2G:移动(GSM)+联通(GSM);2G:电信(CDMA)"
},
{
"k": "2G网络制式",
"v": "2G:GSM 850/900/1800/1900;2G:CDMA 800;3G:TD-SCDMA 1900/2000;3G:CDMA2000;3G:WCDMA:850/900/1700/1900/2100MHz"
}
]
},
{
"group": "存储",
"params": [
{
"k": "机身内存",
"v": "4GB"
},
{
"k": "储存卡类型",
"v": "支持MicroSD(TF)"
}
]
}
]

编辑商品

规格参数的回显

编辑商品时通过商品id查询规格参数数据

前台js代码(item-list.jsp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//加载商品规格
$.getJSON('/rest/item/param/item/'+data.id,function(_data){
if(_data && _data.status == 200 && _data.data && _data.data.paramData){
$("#itemeEditForm .params").show();
$("#itemeEditForm [name=itemParams]").val(_data.data.paramData);
$("#itemeEditForm [name=itemParamId]").val(_data.data.id);

//回显商品规格
var paramData = JSON.parse(_data.data.paramData);

var html = "<ul>";
for(var i in paramData){
var pd = paramData[i];
html+="<li><table>";
html+="<tr><td colspan=\"2\" class=\"group\">"+pd.group+"</td></tr>";

for(var j in pd.params){
var ps = pd.params[j];
html+="<tr><td class=\"param\"><span>"+ps.k+"</span>: </td><td><input autocomplete=\"off\" type=\"text\" value='"+ps.v+"'/></td></tr>";
}

html+="</li></table>";
}
html+= "</ul>";
$("#itemeEditForm .params td").eq(1).html(html);
}
});
后台实现:

访问URL: /rest/item/param/item/{itemId}

controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.migo.controller;

import com.migo.pojo.ItemParamItem;
import com.migo.service.ItemParamItemService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
* Author 知秋
* Created by kauw on 2016/11/14.
*/
@Controller
@RequestMapping("item/param/item")
public class ItemParamItemController {
private static final Logger logger= LoggerFactory.getLogger(ItemParamItemController.class);

@Autowired
private ItemParamItemService itemParamItemService;
/**
* 根据商品Id查询商品规格参数数据
*/
@RequestMapping(value = "{itemId}",method = RequestMethod.GET)
public ResponseEntity<ItemParamItem> showItemParam(@PathVariable("itemId") Long itemId){

try {
if(logger.isInfoEnabled()){
logger.info("根据商品Id查询商品规格参数数据 itemId = {}",itemId);
}
ItemParamItem example=new ItemParamItem();
example.setItemId(itemId);
ItemParamItem itemParamItem = this.itemParamItemService.queryOne(example);
if (null==itemParamItem){
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
return ResponseEntity.ok(itemParamItem);
} catch (Exception e) {
logger.error("根据商品Id查询商品规格参数数据 失败 itemId = {}",itemId,e);
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
}

运行项目:发现无法回显商品描述,还有商品参数回显404 后台日志信息:

1
2
3
4
5
6
7
8
9
10
11
2016-11-15 21:55:59,022 [http-bio-8080-exec-10] [com.migo.controller.ItemParamItemController]-[INFO] 根据商品Id查询商品规格参数数据 itemId = 147921564322726  //开始!!!!!!!!!!!
2016-11-15 21:55:59,022 [http-bio-8080-exec-10] [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Creating new transaction with name [com.migo.service.ItemParamItemService.queryOne]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
2016-11-15 21:55:59,026 [http-bio-8080-exec-10] [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Acquired Connection [com.mysql.jdbc.JDBC4Connection@5f46a96d] for JDBC transaction
2016-11-15 21:55:59,026 [http-bio-8080-exec-10] [org.springframework.jdbc.datasource.DataSourceUtils]-[DEBUG] Setting JDBC Connection [com.mysql.jdbc.JDBC4Connection@5f46a96d] read-only
2016-11-15 21:55:59,026 [http-bio-8080-exec-10] [org.springframework.jdbc.datasource.DataSourceTransactionManager]-[DEBUG] Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@5f46a96d] to manual commit
2016-11-15 21:55:59,027 [http-bio-8080-exec-10] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Creating a new SqlSession
2016-11-15 21:55:59,027 [http-bio-8080-exec-10] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3fd7b476]
2016-11-15 21:55:59,027 [http-bio-8080-exec-10] [org.mybatis.spring.transaction.SpringManagedTransaction]-[DEBUG] JDBC Connection [com.mysql.jdbc.JDBC4Connection@5f46a96d] will be managed by Spring
2016-11-15 21:55:59,028 [http-bio-8080-exec-10] [com.migo.mapper.ItemParamItemMapper.selectOne]-[DEBUG] ==> Preparing: SELECT created,updated,id,item_id,param_data FROM tb_item_param_item WHERE item_id = ? //发送sql语句!!!!!!
2016-11-15 21:55:59,028 [http-bio-8080-exec-10] [com.migo.mapper.ItemParamItemMapper.selectOne]-[DEBUG] ==> Parameters: 147921564322726(Long) //传递参数 !!!!!
2016-11-15 21:55:59,028 [http-bio-8080-exec-10] [com.migo.mapper.ItemParamItemMapper.selectOne]-[DEBUG] <== Total: 0 //查询结果!!!!!!!

查后台数据库,发现新增加商品id正常,但是desc 和商品规格参数所对应的商品id为0,遂修改新增商品service代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//desc参考前端页面传过来的数据是序列化成字符串的
public Boolean saveItem(Item item,String desc,String itemParams){
// 1、生成商品id
long itemId = IDUtils.genItemId();
// 2、对TbItem对象补全属性。
item.setId(itemId);

//'商品状态,1-正常,2-下架,3-删除'
item.setStatus(1);


//保存商品数据
Integer save = super.save(item);

ItemDesc itemDesc=new ItemDesc();
itemDesc.setItemDesc(desc);
itemDesc.setItemId(itemId);

//保存商品描述数据
Integer save1 = this.itemDescService.save(itemDesc);

//保存商品规格参数数据
ItemParamItem itemParamItem=new ItemParamItem();
itemParamItem.setItemId(itemId);
itemParamItem.setParamData(itemParams);
Integer save2 = this.itemParamItemService.save(itemParamItem);
return save.intValue()==1&&save1.intValue()==1&&save2==1;

}

接着查询,返回数据显示正常,但是页面显示不正确:

查看前端js代码发现,为迭代完全,真坑,遂修改:

因为restful风格之后,完全可以直接拿到参数了,无须中间多那一层,以前是做了一层封装,请参考 migo商城第一版 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//加载商品规格
$.getJSON('/rest/item/param/item/'+data.id,function(_data){

$("#itemeEditForm .params").show();
$("#itemeEditForm [name=itemParams]").val(_data.paramData);
$("#itemeEditForm [name=itemParamId]").val(_data.id);

//回显商品规格
var paramData = JSON.parse(_data.paramData);

var html = "<ul>";
for(var i in paramData){
var pd = paramData[i];
html+="<li><table>";
html+="<tr><td colspan=\"2\" class=\"group\">"+pd.group+"</td></tr>";

for(var j in pd.params){
var ps = pd.params[j];
html+="<tr><td class=\"param\"><span>"+ps.k+"</span>: </td><td><input autocomplete=\"off\" type=\"text\" value='"+ps.v+"'/></td></tr>";
}

html+="</li></table>";
}
html+= "</ul>";
$("#itemeEditForm .params td").eq(1).html(html);

});

migo.init({
"pics" : data.image,
"cid" : data.cid,
fun:function(node){
migo.changeItemParam(node, "itemeEditForm");
}
});
}
}).window("open");

最终结果展示:

最后,更新规格参数数据

后台实现:

ItemParamItemService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.migo.service;

import com.migo.mapper.ItemParamItemMapper;
import com.migo.pojo.ItemParamItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;

/**
* Author 知秋
* Created by kauw on 2016/11/14.
*/
@Service
public class ItemParamItemService extends BaseService<ItemParamItem> {
@Autowired
private ItemParamItemMapper itemParamItemMapper;

/**
* 更新商品规格参数数据
* @param itemId
* @param itemParams
* @return
*/
public Integer updateItemParamItem(Long itemId, String itemParams) {
ItemParamItem itemParamItem=new ItemParamItem();
itemParamItem.setParamData(itemParams);
itemParamItem.setUpdated(new Date());

//更新
Example example=new Example(ItemParamItem.class);
example.createCriteria().andEqualTo("itemId",itemId);
return this.itemParamItemMapper.updateByExampleSelective(itemParamItem,example);
}
}

ItemService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 商品修改
*/
public Boolean updateItem(Item item,String desc,String itemParams){
//强制设置不能更新的字段为空,防止恶意修改
item.setStatus(null);
item.setCreated(null);

Integer change1 = super.updateSelective(item);

//更新商品描述
ItemDesc itemDesc=new ItemDesc();
itemDesc.setItemId(item.getId());
itemDesc.setItemDesc(desc);
Integer change2 = this.itemDescService.updateSelective(itemDesc);

Integer change3 = this.itemParamItemService.updateItemParamItem(item.getId(), itemParams);

return change1.intValue()==1&&change2.intValue()==1&&change3.intValue()==1;

}

ItemController 修改实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 更新商品数据
*/
@RequestMapping(method = RequestMethod.PUT)
public ResponseEntity<Void> updateItem(Item item, @RequestParam("desc") String desc,
@RequestParam("itemParams") String itemParams){
if (LOGGER.isInfoEnabled()) {
LOGGER.info("修改商品,item = {}, desc = {}", item, desc);
}
/**
* TODO 校验以后完善
*/
if (item.getPrice() == null || item.getPrice().intValue() == 0) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("修改商品时用户输入的参数不合法,item = {}, desc = {}", item, desc);
}
// 参数有误,返回400
//ResponseEntity<Void> build();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}

try {
Boolean updateItem = this.itemService.updateItem(item, desc,itemParams);
if (updateItem) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("修改商品成功! id = {}", item.getId());
}
//CREATED(201, "Created"),
return ResponseEntity.status(HttpStatus.CREATED).build();
}
} catch (Exception e) {
LOGGER.error("修改商品失败! item = " + item + ", desc = " + desc, e);
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}

启动项目测试,后台日志分析:

通过日志,能看到很多东西,可见添加日志代码的重要性和查看日志的重要性,很多bug都是通过日志发现解决的

您的支持将鼓励我继续创作!